#include <QDebug>
#include <QToolTip>
#include "GLDisplay.h"
#include <QMatrix4x4>
#include <QtOpenGL>
#include <GL/glu.h>
#include <Qt>

#define MINI(a,b) ((a) < (b) ? (a) : (b))

float GLDisplay::xpos = 0;
float GLDisplay::ypos = 0;
float GLDisplay::zpos = 0;
float GLDisplay::xrot = 0;
float GLDisplay::yrot = 0;
float GLDisplay::angle = 0;

GLDisplay::GLDisplay(QWidget *parent) : QGLWidget(parent),
    rigthPressedPoint(NULLPOINT),
    leftPressedPoint(NULLPOINT), zoom(1.0)
{
    setStyleSheet("border: 2px solid black;");
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setFocusPolicy(Qt::ClickFocus);

    salvarEye = false;
    eye.setX(0);
    eye.setY(0);
    eye.setZ(-15);
    lookAt.setX(0);
    lookAt.setY(0);
    lookAt.setZ(0);
    up.setX(0);
    up.setY(-1);
    up.setZ(0);
}

GLDisplay::~GLDisplay()
{
}


void GLDisplay::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    //glShadeModel( GL_FLAT );
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );	// specify implementation-specific hints

    glClearDepth( 1.0 );					// specify the clear value for the depth buffer
    glDepthFunc( GL_LEQUAL );
    //glDisable(GL_CULL_FACE);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

}

void GLDisplay::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
}

float GLDisplay::xDist(float aspect)
{
    if(aspect < 1)
        return (0.5)*zoom;
    else
        return (0.5*aspect)*zoom;
}

float GLDisplay::yDist(float aspect)
{
    if(aspect > 1)
        return (0.5)*zoom;
    else
        return (0.5*(1/aspect))*zoom;
}

void GLDisplay::paintGL()
{
    float aspect = width()*1.0/height();

    float xdist = xDist(aspect);
    float ydist = yDist(aspect);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //glOrtho(-xdist*3.0, xdist*3.0, -ydist*3.0, +ydist*3.0, 5.0, 50); // projecao paralela
    //glFrustum(-xdist, xdist, -ydist, +ydist, 5.0, 50); // projecao em perspectiva
    gluPerspective(11.5, xdist/ydist, 5.0, 50.0); // faz o mesmo que o glFrustum, soh muda a maneira de passar o que ele precisa

    glMatrixMode(GL_MODELVIEW);

    glClearColor( 0.6, 0.6, 0.6, 1.0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glRotatef(xrot, 1.0, 0.0, 0.0);  //rotate our camera on teh  x-axis (left and right)
    glRotatef(yrot, 0.0, 1.0, 0.0);  //rotate our camera on the y-axis (up and down)
    glTranslated(-xpos, -ypos, -zpos); //translate the screen to the position of our camera

    QQuaternion t = interactiveQuartenion();
    QQuaternion rotationVector = QQuaternion::fromAxisAndAngle(QVector3D(t.x(), t.y(), t.z()), degreeFromCos(t.scalar()));
    QVector3D v = rotationVector.rotatedVector(QVector3D(eye.x(), eye.y(), eye.z()));

    if (salvarEye)
    {
       eye = v;
       salvarEye = false;
    }

    gluLookAt(v.x(), v.y(), v.z(), lookAt.x(), lookAt.y(), lookAt.z(), up.x(), up.y(), up.z());

    emit lightSetup();
    emit drawModel();

    glFlush();
}

void GLDisplay::mousePressEvent ( QMouseEvent * event )
{
//  Garante que somente 1 botao estara pressionado e
//  cancela a operacao anterior caso o outro seja pressionado
    if(event->button() == Qt::RightButton)
    {
        if(leftPressedPoint != NULLPOINT)
        {
            leftPressedPoint = NULLPOINT;
            rigthPressedPoint = NULLPOINT;
            emit mouseCancel();
        }else
        {
            rigthPressedPoint = event->pos();
        }
        event->accept();
    }else if(event->button() == Qt::LeftButton)
    {
        if(rigthPressedPoint != NULLPOINT)
        {
            leftPressedPoint = NULLPOINT;
            rigthPressedPoint = NULLPOINT;
            emit mouseCancel();
        }else
        {
            leftPressedPoint = event->pos();
        }
        event->accept();
    }else
        event->ignore();
}

void GLDisplay::mouseReleaseEvent ( QMouseEvent * event )
{
    if(event->button() == Qt::RightButton)
    {
        if(rigthPressedPoint != NULLPOINT)
        {
            emit mouseRigthFinish(rigthPressedPoint, event->pos());
            rigthPressedPoint = NULLPOINT;
        }
        event->accept();
    }else if(event->button() == Qt::LeftButton)
    {
        if(leftPressedPoint != NULLPOINT)
        {
            emit mouseLefthFinish(leftPressedPoint, event->pos());
            leftPressedPoint = NULLPOINT;
        }
    }else
        event->ignore();
}

void GLDisplay::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::RightButton)
    {
        if(rigthPressedPoint != NULLPOINT)
        {
            emit mouseRigthMove(rigthPressedPoint, event->pos());
        }
        event->accept();
    }else if(event->buttons() == Qt::LeftButton)
    {
        if(leftPressedPoint != NULLPOINT)
        {
            emit mouseLeftMove(leftPressedPoint, event->pos());
        }
        event->accept();
    }else
        event->ignore();
}

void GLDisplay::keyboard (int key) {
    if (key == Qt::Key_E)
    {
        xrot += 1;
        if (xrot > 360) xrot -= 360;
    }

    if (key == Qt::Key_Q)
    {
        xrot -= 1;
        if (xrot < -360) xrot += 360;
    }

    if (key == Qt::Key_W)
    {
        float xrotrad, yrotrad;
        yrotrad = (yrot / 180 * 3.141592654f);
        xrotrad = (xrot / 180 * 3.141592654f);
        xpos += float(sin(yrotrad)) ;
        zpos -= float(cos(yrotrad)) ;
        ypos -= float(sin(xrotrad)) ;
    }

    if (key == Qt::Key_S)
    {
        float xrotrad, yrotrad;
        yrotrad = (yrot / 180 * 3.141592654f);
        xrotrad = (xrot / 180 * 3.141592654f);
        xpos -= float(sin(yrotrad));
        zpos += float(cos(yrotrad)) ;
        ypos += float(sin(xrotrad));
    }

    if (key == Qt::Key_D)
    {
        yrot += 1;
        if (yrot >360) yrot -= 360;
    }

    if (key == Qt::Key_A)
    {
        yrot -= 1;
        if (yrot < -360)yrot += 360;
    }

    if (key == Qt::Key_Delete) {
        //emit deletePressed();
    }

    if (key==Qt::Key_Escape)
    {
        exit(0);
    }
}

void GLDisplay::setInteractiveQuartenion(const QQuaternion& quaternion)
{
    m_interactiveQuartenion = quaternion;
}

const QQuaternion& GLDisplay::interactiveQuartenion(void)const
{
    return m_interactiveQuartenion;
}

double GLDisplay::degreeFromCos(double _cos)const
{
    return (acos(_cos)*180.0)/M_PI;
}

void GLDisplay::salvarEyeRotation()
{
    salvarEye = true;
}

QVector3D GLDisplay::getEye()
{
    return eye;
}

QVector3D GLDisplay::getLookAt()
{
    return lookAt;
}

QVector3D GLDisplay::getUp()
{
    return up;
}
